package com.k.kppcloud.gateway.config;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.k.kppcloud.gateway.util.json.JsonUtils;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * @author kivil
 */
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {
    private static final org.slf4j.Logger log = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);

    private ApplicationEventPublisher publisher;
    private NacosConfigManager nacosConfigManager;
    private String dataId;
    private String group;

    public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigManager manager, String nDataId, String nGroup) {
        this.publisher = publisher;
        this.nacosConfigManager = manager;
        this.dataId = nDataId;
        this.group = nGroup;
        addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            log.info("getRouteDefinitions");
            String content = nacosConfigManager.getConfigService().getConfig(dataId, group, 5000);
            List<RouteDefinition> routeDefinitions = getListByStr(content);
            log.info("getRouteDefinitions : routeDefinitions:{}", routeDefinitions);
            return Flux.fromIterable(routeDefinitions);
        } catch (NacosException | JsonProcessingException e) {
            log.error("getRouteDefinitions by nacos error", e);
        }
        return Flux.fromIterable(Collections.EMPTY_LIST);
    }

    /**
     * 添加Nacos监听
     */
    private void addListener() {
        try {
            nacosConfigManager.getConfigService().addListener(dataId, group, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("listener config:{}", configInfo);
                    publisher.publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    private List<RouteDefinition> getListByStr(String content) throws JsonProcessingException {
        if (StringUtils.isNotEmpty(content)) {
            return JsonUtils.Jackson.getMAPPER().readValue(content, new TypeReference<List<RouteDefinition>>() {
            });
        }
        return Collections.emptyList();
    }
}
